import javax.swing.JDialog;
import javax.swing.JTable;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.AbstractListModel;
import javax.swing.ListModel;
import javax.swing.ListCellRenderer;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.border.SoftBevelBorder;
import java.awt.Font;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;


/**
 * AdjMatrixDialog provides a tabular dialog to the user for editing the 
 * weights of the edges.
 *
 * @version 1.0
 * @author P.Jaya Krishna
 */
class AdjMatrixDialog extends JDialog
{
	private GFrame gFrame;
	private JTable adjMatrixTable;
	
	/** 
	 * Creates an AdjMatrixDialog object for the given frame.
	 */
	public AdjMatrixDialog(GFrame gFrame)
	{
		super(gFrame, true);
		this.gFrame = gFrame;
		
		JPanel buttonPanel = new JPanel();
		JButton ok = new JButton("Ok");
		JButton cancel = new JButton("Cancel");
		buttonPanel.add(ok);
		buttonPanel.add(cancel);
		
		if(gFrame.gPanel.getGraph().isDirected())
			setTitle("Adjacency Matrix -- Directed Graph");
		else
			setTitle("Adjacency Matrix -- Undirected Graph");
		
		// populate the table from adjacency matrix of the corresponding gPanel
		// and set various properties of the table
		if(gFrame.gPanel.getGraph().numVertices() != 0)
		{
			GTableModel tableModel = new GTableModel();
			adjMatrixTable = new JTable(tableModel);
			
			adjMatrixTable.setDefaultEditor(Integer.class, new IntegerEditor(0, 1000));
			adjMatrixTable.setPreferredScrollableViewportSize(new Dimension(500, 150));
			adjMatrixTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
			adjMatrixTable.setRowSelectionAllowed(false);
			
			JList rowHeader = new JList(tableModel.listModel);
			rowHeader.setFixedCellWidth(50);
			rowHeader.setFixedCellHeight(adjMatrixTable.getRowHeight()+ adjMatrixTable.getRowMargin()-1);
    		rowHeader.setCellRenderer(new RowHeaderRenderer(adjMatrixTable));
			
			JScrollPane scrollPane = new JScrollPane(adjMatrixTable);
			scrollPane.setRowHeaderView(rowHeader);
			getContentPane().add(scrollPane);
			
		}
		else // if there are no vertices in the graph
		{
			this.setPreferredSize(new Dimension(325, 150));
			
			JLabel oops = new JLabel("           Oops!! The graph is still empty...");
			oops.setFont(new Font("Garmond", Font.BOLD, 15));
			getContentPane().add(oops);
			this.setResizable(false);
		}
		
		getContentPane().add(buttonPanel,BorderLayout.SOUTH);
		ok.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent ae)
			{
				updateAdjMatrix();
				dispose();
			}
		});
		cancel.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent ae)
			{
				dispose();
			}
		});
		
		getRootPane().setDefaultButton(ok);
		setLocation(100,100);
		pack();
		setVisible(true);
	}
	
	/**
	 * Updates the adjacency matrix of the corresponding gPanel's graph.
	 */
	public void updateAdjMatrix()
	{
		try
		{
			gFrame.gPanel.addUndo();
			gFrame.gPanel.getGraph().setAdjMatrix(adjMatrixTable);
			gFrame.gPanel.repaint();
		}
		catch(IllegalVertexException e)
		{
			// Not a problem even if failed.
		}
		
	}
	
	// The table model for creating an adjMatrixTable.
	private class GTableModel extends AbstractTableModel
	{
		private String[] columnNames = gFrame.gPanel.getGraph().getColNames();
		private Object[][] data = gFrame.gPanel.getGraph().getRowData();
		ListModel listModel;
		
		GTableModel()
		{
			listModel = new AbstractListModel()
			{
				public int getSize()
				{
					return columnNames.length;
				}
				
				public Object getElementAt(int index)
				{
					return columnNames[index];
				}
			};
		}
		
		public int getColumnCount()
		{
			return columnNames.length;
		}
		
		public int getRowCount()
		{
			return data.length;
		}
		
		public String getColumnName(int col)
		{
			return columnNames[col];
		}
		
		public Object getValueAt(int row, int col)
		{
			return data[row][col];
		}
		
		public Class getColumnClass(int c)
		{
			return getValueAt(0, c).getClass();
		}
		
		public boolean isCellEditable(int row, int col)
		{
			if (col == row)
			{
				return false;
			}
			else
			{
				return true;
			}
		}
		
		public void setValueAt(Object value, int row, int col)
		{
			data[row][col] = value;
			fireTableCellUpdated(row, col);
			
			if(!gFrame.gPanel.getGraph().isDirected())
			{
				data[col][row] = value;
				fireTableCellUpdated(col, row);
			}
		}
	}
	
	class RowHeaderRenderer extends JLabel implements ListCellRenderer
	{
		
		RowHeaderRenderer(JTable table)
		{
			JTableHeader header = table.getTableHeader();
			setOpaque(true);
			setBorder(new SoftBevelBorder(SoftBevelBorder.RAISED));
			setHorizontalAlignment(CENTER);
			setForeground(header.getForeground());
			setBackground(header.getBackground());
			setFont(header.getFont());
		}
		
		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
		{
			setText((value == null) ? "" : value.toString());
			return this;
		}
	}
}